package net.jwtools.tmt.dao.hibernate;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import net.jwtools.tmt.domain.IVisit;
import net.jwtools.tmt.domain.MainVisit;
import net.jwtools.tmt.domain.Person;
import net.jwtools.tmt.domain.ReVisit;
import net.jwtools.tmt.domain.Status;
import net.jwtools.tmt.domain.Territory;
import net.jwtools.tmt.util.ExtendedControl;

import org.hibernate.NonUniqueObjectException;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.jfree.data.time.Week;

public class VisitHibernateDAO extends AbstractSpringDao {
	protected ResourceBundle bundle = ResourceBundle.getBundle(
			"net/jwtools/tmt/ui/messages", new ExtendedControl());

	public IVisit find(Long id) {
		return (IVisit) super.find(IVisit.class, id);
	}

	
	public void saveOrUpdate(IVisit visit) {
		System.out.println("saving visit:"+visit.getId()+"="+visit );
		try {
			super.saveOrUpdate(visit);
		} catch (NonUniqueObjectException e) {
			// try to merge
			getHibernateTemplate().merge(visit);
		}
	}

	public void delete(IVisit visit) {
		super.delete(visit);
	}

	@SuppressWarnings("unchecked")
	public List<IVisit> findAll() {
		return (List<IVisit>) super.findAll(IVisit.class);
	}

	@SuppressWarnings("unchecked")
	public List<IVisit> findAllOutstandingMainVisitsFor(Person person) {
		DetachedCriteria crit = DetachedCriteria.forClass(MainVisit.class);
		crit.add(Restrictions.eq("checkoutBy", person));
		crit.add(Restrictions.isNull("checkinDate"));
		return (List<IVisit>) super.findByCriteria(crit);
	}

	@SuppressWarnings("unchecked")
	public List<IVisit> findAllOutstandingReVisitsFor(Person person) {
		DetachedCriteria crit = DetachedCriteria.forClass(ReVisit.class);
		crit.add(Restrictions.eq("checkoutBy", person));
		crit.add(Restrictions.isNull("checkinDate"));
		return (List<IVisit>) super.findByCriteria(crit);
	}

	public Integer countAllOutstandingReVisits() {
		DetachedCriteria crit = DetachedCriteria.forClass(ReVisit.class);
		crit.setProjection(Projections.rowCount());
		return ((Integer) super.findByCriteria(crit).get(0)).intValue();
	}

	public Integer countAllOutstandingMainVisits() {
		DetachedCriteria crit = DetachedCriteria.forClass(MainVisit.class);
		crit.setProjection(Projections.rowCount());
		return ((Integer) super.findByCriteria(crit).get(0)).intValue();
	}

	@SuppressWarnings("unchecked")
	public List<IVisit> findAllOutstandingFor(Person person) {
		DetachedCriteria crit = DetachedCriteria.forClass(IVisit.class);
		crit.add(Restrictions.eq("checkoutBy", person));
		crit.add(Restrictions.isNull("checkinDate"));
		return (List<IVisit>) super.findByCriteria(crit);
	}
	
	@SuppressWarnings("unchecked")
	public List<IVisit> findAllOutstanding() {
		DetachedCriteria crit = DetachedCriteria.forClass(IVisit.class);
		crit.add(Restrictions.isNull("checkinDate"));
		crit.add(Restrictions.eq("status", Status.ACTIVE));
		crit.createCriteria("territory").addOrder(Order.asc("number"));
		return (List<IVisit>) super.findByCriteria(crit);
	}
	@SuppressWarnings("unchecked")
	public List<IVisit> findAllFor(Person person) {
		DetachedCriteria crit = DetachedCriteria.forClass(IVisit.class);
		crit.add(Restrictions.eq("checkoutBy", person));
		return (List<IVisit>) super.findByCriteria(crit);
	}

	@SuppressWarnings("unchecked")
	public List<IVisit> findAllCompleted(Territory territory) {
		DetachedCriteria crit = DetachedCriteria.forClass(MainVisit.class);
		crit.add(Restrictions.eq("territory", territory));
		crit.add(Restrictions.isNotNull("readyDate"));
		crit.addOrder(Order.desc("readyDate"));
		return (List<IVisit>) super.findByCriteria(crit);
	}

	@SuppressWarnings("unchecked")
	public List<IVisit> findAllBelongingTo(IVisit visit) {
		DetachedCriteria crit = DetachedCriteria.forClass(IVisit.class);
		crit.add(Restrictions.eq("belongsTo", visit));
		crit.addOrder(Order.asc("checkoutDate"));
		List<IVisit> visits = (List<IVisit>) super.findByCriteria(crit);
		return visits;
	}

	@SuppressWarnings("unchecked")
	public Integer countAllCompletedMainVisits() {
		DetachedCriteria crit = DetachedCriteria.forClass(MainVisit.class);
		crit.add(Restrictions.isNotNull("readyDate"));
		crit.setProjection(Projections.rowCount());
		return ((Integer) super.findByCriteria(crit).get(0)).intValue();
	}

	@SuppressWarnings("unchecked")
	public Integer countAllCompletedReVisits() {
		DetachedCriteria crit = DetachedCriteria.forClass(ReVisit.class);
		crit.add(Restrictions.isNotNull("checkinDate"));
		crit.setProjection(Projections.rowCount());
		return ((Integer) super.findByCriteria(crit).get(0)).intValue();
	}

	@SuppressWarnings("unchecked")
	public List<IVisit> findAllCompleted() {
		DetachedCriteria crit = DetachedCriteria.forClass(IVisit.class);
		crit.add(Restrictions.isNotNull("checkinDate"));
		crit.add(Restrictions.eq("status", Status.ACTIVE));
		return (List<IVisit>) super.findByCriteria(crit);
	}

	public Map<Week, Integer> findCheckedOutMainVisitsBetween(Date start,
			Date end) {
		DetachedCriteria crit = DetachedCriteria.forClass(MainVisit.class);
		//crit.add(Restrictions.between("checkoutDate", start, end));
		crit.setProjection(Projections.property("checkoutDate"));
		Map<Week, Integer> weekMap = new HashMap<Week, Integer>();
		List<Date> dates = (List<Date>) super.findByCriteria(crit);
		System.out.println(dates.size()+" >> "+dates);
		for (Date checkoutDate : dates) {
			Week a = new Week(checkoutDate);
			
			if (weekMap.containsKey(a)) {
				Integer weekCount = weekMap.get(a);
				weekCount++;
				weekMap.put(a, weekCount);
			} else {
				weekMap.put(a, 1);
			}
		}
		System.out.println(weekMap);
		return weekMap;
	}
	public Map<Week, Integer> findCheckedOutReVisitsBetween(Date start,
			Date end) {
		DetachedCriteria crit = DetachedCriteria.forClass(ReVisit.class);
		//crit.add(Restrictions.between("checkoutDate", start, end));
		crit.setProjection(Projections.property("checkoutDate"));
		Map<Week, Integer> weekMap = new HashMap<Week, Integer>();
		List<Date> dates = (List<Date>) super.findByCriteria(crit);
		System.out.println(dates.size()+" >> "+dates);
		for (Date checkoutDate : dates) {
			Week a = new Week(checkoutDate);
			
			if (weekMap.containsKey(a)) {
				Integer weekCount = weekMap.get(a);
				weekCount++;
				weekMap.put(a, weekCount);
			} else {
				weekMap.put(a, 1);
			}
		}
		System.out.println(weekMap);
		return weekMap;
	}

}
